package com.hyt.it.ogt.controller.ykcj.zs;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.hyt.common.apiInfor.ApiResponse;
import com.hyt.core.util.FastJsonUtil;
import com.hyt.core.util.UUIDUtils;
import com.hyt.exception.annotation.ThrowsAdvice;
import com.hyt.exception.exception.BusinessLogicException;
import com.hyt.it.ogt.common.config.ApiVersionConstant;
import com.hyt.it.ogt.ykcj.common.constant.Constants;
import com.hyt.it.ogt.ykcj.common.core.domain.AjaxResult;
import com.hyt.it.ogt.ykcj.common.enums.ExamResultDownLoadFileTypeEnum;
import com.hyt.it.ogt.ykcj.common.enums.ExamResultDownLoadStatusEnum;
import com.hyt.it.ogt.ykcj.common.exception.CustomException;
import com.hyt.it.ogt.ykcj.common.progress.ImportCertificateExamineesPhotoLockKeyCreator;
import com.hyt.it.ogt.ykcj.domain.exam.ExamResultDataDownLoadRecord;
import com.hyt.it.ogt.ykcj.domain.param.CertificatePageParam;
import com.hyt.it.ogt.ykcj.domain.zs.ZsExamineeInfo;
import com.hyt.it.ogt.ykcj.domain.zs.dto.ImportCertificateExamineesDataDTO;
import com.hyt.it.ogt.ykcj.domain.zs.dto.ZsInfoDTO;
import com.hyt.it.ogt.ykcj.domain.zs.vo.ImportCertificateExamineesMessageVO;
import com.hyt.it.ogt.ykcj.domain.zs.vo.ZsExamInfoVO;
import com.hyt.it.ogt.ykcj.domain.zs.vo.ZsExamScoreLineVO;
import com.hyt.it.ogt.ykcj.domain.zs.vo.ZsInfoVO;
import com.hyt.it.ogt.ykcj.service.exam.IExamResultDataDownLoadRecordService;
import com.hyt.it.ogt.ykcj.service.zs.IZsExamineeInfoService;
import com.hyt.it.ogt.ykcj.service.zs.IZsInfoService;
import com.hyt.it.ogt.ykcj.utils.RedisLock;
import com.hyt.loginfo.controller.BaseLoginController;
import com.hyt.loginfo.model.User;
import com.hyt.loginfo.service.IBaseLoginService;
import com.hyt.progress.creator.anno.ProgressAnno;
import com.hyt.swagger.ApiVersion;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;
import java.util.UUID;

/**
 * @program: it-ogt-ykcj
 * @description: 证书控制器
 * @author: Yang HuanKun
 * @create: 2022-06-21 10:18
 **/
@Api(tags = "zs.2.证书管理", value = "证书控制器")
@ApiSort(value = 402)
@Slf4j
@RestController
@RequestMapping("/certificate")
public class CertificateController extends BaseLoginController {

    @Resource
    private IZsInfoService iZsInfoService;
    @Resource
    private IBaseLoginService baseLoginService;
    @Resource
    private RedisLock redisLock;
    @Autowired
    private IExamResultDataDownLoadRecordService examResultDataDownLoadRecordService;
    @Resource
    private IZsExamineeInfoService iZsExamineeInfoService;

    @ApiOperation(
            value = "下载证书人员导入模板",
            notes = "20000:成功;"
    )
    @ApiOperationSort(value = 1)
    @ApiVersion(group = ApiVersionConstant.V2_4_2)
    @GetMapping("/downloadExamineeImportTemplate")
    public void downloadExamineeImportTemplate(@ApiParam(value = "证书ID") @RequestParam String infoId, HttpServletResponse response) throws Exception {
        iZsInfoService.downloadExamineeImportTemplate(infoId, response);
    }

    @ApiOperation(
            value = "下载导入证书编码模板",
            notes = "20000:成功;"
    )
    @ApiOperationSort(value = 2)
    @ApiVersion(group = ApiVersionConstant.V2_4_2)
    @GetMapping("/downloadCertificateCodeTemplate")
    public void downloadCertificateCodeTemplate(@ApiParam(value = "证书ID") @RequestParam String infoId, HttpServletResponse response) throws Exception {
        iZsInfoService.downloadCertificateCodeTemplate(infoId, response);
    }

    @ApiOperation(
            value = "发放证书",
            notes = "20000:成功;",
            response = Boolean.class
    )
    @ApiOperationSort(value = 3)
    @ApiVersion(group = ApiVersionConstant.V2_4_2)
    @ProgressAnno(timeoutSeconds = 60 * 60 * 5, errorCode = 52402515)
    @GetMapping("/issueCertificate")
    public void issueCertificate(@ApiParam(value = "证书ID") @RequestParam String infoId) {
        //获取证书发放锁
        String key = Constants.BATCH_LOCK_KEY_HEAD + infoId;
        String consumerId = UUID.randomUUID().toString();
        boolean lockSuccess = redisLock.tryLock(key, consumerId, Constants.LOCK_TIME);
        if (!lockSuccess) {
            BusinessLogicException.throwException(52402514, "证书正在发放，请等待数据处理完成！");
        }
        iZsInfoService.issueCertificate(infoId, consumerId);
    }

    @ApiOperation(
            value = "导入证书数据文件校验",
            notes = "20000:成功;",
            response = ImportCertificateExamineesMessageVO.class
    )
    @ApiOperationSort(value = 3)
    @ApiVersion(group = ApiVersionConstant.V2_4_2)
    @PostMapping("/importCertificateExamineesCheck")
    public AjaxResult importCertificateExamineesCheck(@ApiParam(value = "导入数据文件") @RequestParam("file") MultipartFile file,
                                                      @ApiParam(value = "证书ID") @RequestParam String infoId) throws IOException {
        return AjaxResult.success(iZsInfoService.importCertificateExamineesCheck(file, infoId));
    }

    @ApiOperation(
            value = "导入证书人员数据",
            notes = "20000:成功;",
            response = Boolean.class
    )
    @ApiOperationSort(value = 4)
    @ApiVersion(group = ApiVersionConstant.V2_4_2)
    @PostMapping("/importCertificateExamineesData")
    public AjaxResult importCertificateExamineesData(@Validated @RequestBody ImportCertificateExamineesDataDTO requestParam, BindingResult bindingResult) {
        log.debug("# 导入证书人员请求数据：{}", FastJsonUtil.getBeanToJson(requestParam));
        this.checkValid(bindingResult);
        return AjaxResult.success(iZsInfoService.importCertificateExamineesData(requestParam.getCertificateExaminees(), requestParam.getInfoId()));
    }

    @ApiOperation(
            value = "导入考生照片",
            notes = "20000:成功;",
            response = Boolean.class
    )
    @ApiOperationSort(value = 5)
    @ApiVersion(group = ApiVersionConstant.V2_4_9)
    @ProgressAnno(total = 100, timeoutSeconds = 60 * 60 * 5, errorCode = 51150304, canConcurrent = false, lockKeyCreator = ImportCertificateExamineesPhotoLockKeyCreator.class)
    @PostMapping("/importCertificateExamineesPhoto")
    public void importCertificateExamineesPhoto(@ApiParam(value = "导入数据文件URL") @RequestParam String zipFileUrl,
                                                @ApiParam(value = "证书ID") @RequestParam String infoId) throws IOException {
        iZsInfoService.importCertificateExamineesPhoto(zipFileUrl, infoId);
    }

    @ApiOperation(value = "创建证书", notes = "20000:成功;")
    @ApiOperationSort(value = 6)
    @ApiVersion(group = ApiVersionConstant.V2_4_2)
    @ThrowsAdvice(code = 52402601, print = "创建证书异常")
    @PostMapping("/createCertificate")
    public ApiResponse<Object> createCertificate(@RequestBody ZsInfoDTO zsInfoDTO) {
        log.info("# 创建证书请求参数：{}", JSONUtil.toJsonStr(zsInfoDTO));
        // 获取当前登录人用户信息
        User user = baseLoginService.getSysUser();
        if (null == user || StringUtils.isEmpty(user.getId())) {
            return ApiResponse.<Object>builder().code(52411101).build();
        }
        zsInfoDTO.setOfficeId(user.getOfficeid());
        zsInfoDTO.setDeptId(getDeptId());
        ApiResponse<Object> checkResult = iZsInfoService.checkZsData(zsInfoDTO, Boolean.FALSE);
        if (null != checkResult) {
            return checkResult;
        }
        String userId = baseLoginService.getUserId();
        zsInfoDTO.setCreateBy(userId);
        zsInfoDTO.setUpdateBy(userId);
        iZsInfoService.createCertificate(zsInfoDTO);
        return ApiResponse.builder().code(20000).build();
    }

    @ApiOperation(value = "编辑证书", notes = "20000:成功;")
    @ApiOperationSort(value = 7)
    @ApiVersion(group = ApiVersionConstant.V2_4_2)
    @PostMapping("/editCertificate")
    public ApiResponse<Object> editCertificate(@RequestBody ZsInfoDTO zsInfoDTO) {
        try {
            log.info("## editCertificate zsInfoDTO:[{}]", JSONUtil.toJsonStr(zsInfoDTO));
            ApiResponse<Object> checkResult = iZsInfoService.checkZsData(zsInfoDTO, Boolean.TRUE);
            if (null != checkResult) {
                return checkResult;
            }
            String userId = baseLoginService.getUserId();
            zsInfoDTO.setUpdateBy(userId);
            iZsInfoService.editCertificate(zsInfoDTO);
            return ApiResponse.builder().code(20000).build();
        } catch (CustomException e) {
            throw e;
        } catch (Exception e) {
            log.error("editCertificate zsInfoDTO={}, mag={}", zsInfoDTO, e.getMessage());
        }
        return ApiResponse.builder().code(52402701).build();
    }

    @ApiOperation(value = "删除证书",
            notes = "20000:成功;")
    @ApiOperationSort(value = 8)
    @ApiVersion(group = ApiVersionConstant.V2_4_2)
    @GetMapping("/deleteCertificate")
    public ApiResponse<Object> deleteCertificate(@ApiParam(value = "证书ID") @RequestParam String id) {
        String userId = baseLoginService.getUserId();
        iZsInfoService.deleteCertificate(id, userId);
        return ApiResponse.builder().code(20000).build();
    }

    @ApiOperation(value = "获取证书信息详情",
            notes = "20000:成功;", response = ZsInfoVO.class)
    @ApiOperationSort(value = 9)
    @ApiVersion(group = ApiVersionConstant.V2_4_2)
    @GetMapping("/queryCertificateDetail")
    public ApiResponse<Object> queryCertificateDetail(@ApiParam(value = "证书ID") @RequestParam String id) {
        try {
            ZsInfoVO vo = iZsInfoService.queryCertificate(id);
            return ApiResponse.builder().code(20000).data(vo).build();
        } catch (Exception e) {
            log.error("queryCertificate id={}, mag={}", id, e.getMessage());
        }
        return ApiResponse.builder().code(20000).build();
    }

    @ApiOperation(value = "分页获取证书列表",
            notes = "20000:成功;",
            response = ZsInfoVO.class)
    @ApiOperationSort(value = 10)
    @ApiVersion(group = {ApiVersionConstant.V2_4_2, ApiVersionConstant.V2_4_10})
    @GetMapping("/certificatePage")
    public ApiResponse<IPage<ZsInfoVO>> certificatePage(CertificatePageParam param) {
        log.info("## certificatePage request param:{}", JSONUtil.toJsonStr(param));
        param.setSize(param.getPageSize());
        param.setCurrent(param.getPageNum());
        // 获取当前登录人用户信息.
        User user = baseLoginService.getSysUser();
        if (null == user || StringUtils.isEmpty(user.getId())) {
            return ApiResponse.<IPage<ZsInfoVO>>builder()
                    .code(52411101)
                    .build();
        }

        Set<String> deptIds = this.getDeptIds();
        param.setDeptIds(deptIds);

        return ApiResponse.<IPage<ZsInfoVO>>builder()
                .code(20000)
                .data(iZsInfoService.certificatePage(param))
                .build();
    }

    @ApiOperation(value = "获取机构下所有考试信息列表",
            notes = "20000:成功;", response = ZsExamInfoVO.class)
    @ApiOperationSort(value = 11)
    @ApiImplicitParams({
            @ApiImplicitParam(
                    name = "zsId", value = "证书id", dataType = "string", paramType = "query", required = false
            )
    })
    @ApiVersion(group = {ApiVersionConstant.V2_4_2, ApiVersionConstant.V2_4_10})
    @GetMapping("/queryExamByOfficeId")
    public ApiResponse<Object> queryExamByOfficeId(String zsId) {
        // 获取当前登录人用户信息
        User user = baseLoginService.getSysUser();
        if (null == user || StringUtils.isEmpty(user.getId())) {
            return ApiResponse.<Object>builder().code(52411101).build();
        }

        Set<String> deptIds = getDeptIds();

        return ApiResponse.builder()
                .code(20000)
                .data(iZsInfoService.queryExamByOfficeId(deptIds))
                .build();
    }

    @ApiOperation(value = "获取考试结果选项",
            notes = "20000:成功;52421201: 考试未设置分数线信息", response = ZsExamScoreLineVO.class)
    @ApiOperationSort(value = 12)
    @ApiVersion(group = ApiVersionConstant.V2_4_2)
    @GetMapping("/getScoreLine")
    public ApiResponse<Object> getScoreLine(@ApiParam(value = "考试ID") @RequestParam String examId) {
        List<ZsExamScoreLineVO> list = iZsInfoService.getExamScoreLine(examId);
        return ApiResponse.builder().code(20000).data(list).build();
    }

    @ApiOperation(value = "证书(取消)发布",
            notes = "20000:成功;", response = ZsExamScoreLineVO.class)
    @ApiOperationSort(value = 13)
    @ApiVersion(group = ApiVersionConstant.V2_4_2)
    @GetMapping("/setCertificateStatus")
    public ApiResponse<Object> setCertificateStatus(@ApiParam(value = "证书ID") @RequestParam String id, @ApiParam(value = "1-已发布，2-取消发布") @RequestParam Integer status) {
        String userId = baseLoginService.getUserId();
        if (StringUtils.isEmpty(userId)) {
            return ApiResponse.<Object>builder().code(52401131).build();
        }
        Boolean updateResult = iZsInfoService.setCertificateStatus(id, status, userId);
        if (updateResult) {
            return ApiResponse.builder().code(20000).build();
        } else {
            return ApiResponse.builder().code(52401132).build();
        }

    }

    @ApiOperation(value = "证书发布设置，获取证书信息",
            notes = "20000:成功;", response = ZsInfoVO.class)
    @ApiOperationSort(value = 14)
    @ApiVersion(group = ApiVersionConstant.V2_4_2)
    @GetMapping("/examGetZsInfo")
    public ApiResponse<Object> examGetZsInfo(@RequestParam String examId) {
        return ApiResponse.builder().code(20000).data(iZsInfoService.examGetZsInfo(examId)).build();
    }

    @ApiOperation(
            value = "导入证书编码校验",
            notes = "20000:成功;",
            response = ImportCertificateExamineesMessageVO.class
    )
    @ApiOperationSort(value = 15)
    @ApiVersion(group = ApiVersionConstant.V2_4_2)
    @PostMapping("/importCertificateSerialNumberCheck")
    public AjaxResult importCertificateSerialNumberCheck(@ApiParam(value = "导入数据文件") @RequestParam("file") MultipartFile file,
                                                         @ApiParam(value = "证书ID") @RequestParam String infoId) throws IOException {
        return AjaxResult.success(iZsInfoService.importCertificateSerialNumberCheck(file, infoId));
    }

    @ApiOperation(
            value = "导入证书编码数据",
            notes = "20000:成功;",
            response = Long.class
    )
    @ApiOperationSort(value = 16)
    @ApiVersion(group = ApiVersionConstant.V2_4_2)
    @PostMapping("/importCertificateSerialNumberData")
    public AjaxResult importCertificateSerialNumberData(@Validated @RequestBody ImportCertificateExamineesDataDTO requestParam, BindingResult bindingResult) {
        log.debug("# 导入证书编码数据：{}", FastJsonUtil.getBeanToJson(requestParam));
        this.checkValid(bindingResult);
        return AjaxResult.success(iZsInfoService.importCertificateSerialNumberData(requestParam.getCertificateExaminees(), requestParam.getInfoId()));
    }

    @ApiOperation(
            value = "批量下载证书（有电子签章）",
            notes = "20000:成功;"
    )
    @ApiOperationSort(value = 17)
    @ApiVersion(group = ApiVersionConstant.V2_4_2)
    @GetMapping("/batchDownloadCertificate")
    public AjaxResult batchDownloadCertificate(@ApiParam(value = "证书ID") @RequestParam String infoId, HttpServletResponse response) throws Exception {
        // 获取当前登录人用户信息
        User user = baseLoginService.getSysUser();
        if (null == user || StringUtils.isEmpty(user.getId())) {
            return AjaxResult.error(52402171, "获取不到登录账号信息");
        }
        // 记录下载文件
        // 获取文件下载记录下载中，则直接告诉客户下载洪
        ExamResultDownLoadFileTypeEnum fileType = ExamResultDownLoadFileTypeEnum.ZS_BATCH_DOWNLOAD;
        ExamResultDataDownLoadRecord projectDataDownLoadRecord = null;
        try {
            projectDataDownLoadRecord = examResultDataDownLoadRecordService.getExamResultDataDownLoadRecord(infoId, user.getOfficeid(), fileType.getType());
        } catch (Exception e) {
            log.error("## batchDownloadCertificate error", e);
            return AjaxResult.error(52402172, "文件正在下载中请耐心等待");
        }
        if (null != projectDataDownLoadRecord && ExamResultDownLoadStatusEnum.downloading.getStatus().equals(projectDataDownLoadRecord.getStatus())) {
            return AjaxResult.error(52402172, "文件正在下载中请耐心等待");
        }
        if (null != projectDataDownLoadRecord && ExamResultDownLoadStatusEnum.finish.getStatus().equals(projectDataDownLoadRecord.getStatus())) {
            // 获取下载记录的创建时间
            LocalDateTime recordCreateDate = projectDataDownLoadRecord.getCreateDate();
            // 获取项目下的考生最新的时间
            ZsExamineeInfo student = iZsExamineeInfoService.getLastOneStudentByZsId(infoId);
            if (null != student) {
                LocalDateTime studentUpdateDate = student.getUpdateDate();
                if (recordCreateDate.compareTo(studentUpdateDate) > 0) {
                    return AjaxResult.success("成功", projectDataDownLoadRecord.getFileUrl());
                }
            }

        }
        projectDataDownLoadRecord = new ExamResultDataDownLoadRecord();
        projectDataDownLoadRecord.setId(UUIDUtils.newSortUUID());
        projectDataDownLoadRecord.setExamId(infoId);
        projectDataDownLoadRecord.setOfficeId(user.getOfficeid());
        projectDataDownLoadRecord.setDeptId(user.getOrganizationid());
        projectDataDownLoadRecord.setFileType(fileType.getType());
        projectDataDownLoadRecord.setStatus(ExamResultDownLoadStatusEnum.downloading.getStatus());
        projectDataDownLoadRecord.setRemark(fileType.getDesc());
        projectDataDownLoadRecord.setCreateBy(user.getId());
        projectDataDownLoadRecord.setCreateDate(LocalDateTime.now());
        projectDataDownLoadRecord.setUpdateBy(user.getId());
        projectDataDownLoadRecord.setDelFlag(false);
        projectDataDownLoadRecord.setUpdateDate(LocalDateTime.now());
        examResultDataDownLoadRecordService.save(projectDataDownLoadRecord);
        String fileUrl = iZsInfoService.batchDownloadCertificate(infoId, projectDataDownLoadRecord, response);
        if (StringUtils.isNotEmpty(fileUrl)) {
            return AjaxResult.success("成功", fileUrl);
        } else {
            return AjaxResult.error(52402172, "文件正在下载中请耐心等待");
        }
    }

    @ApiOperation(
            value = "批量下载证书（无电子签章）",
            notes = "20000:成功;"
    )
    @ApiOperationSort(value = 18)
    @ApiVersion(group = ApiVersionConstant.V2_4_9)
    @GetMapping("/batchDownloadCertificateNoSignature")
    public AjaxResult batchDownloadCertificateNoSignature(@ApiParam(value = "证书ID") @RequestParam String infoId, HttpServletResponse response) throws Exception {
        // 获取当前登录人用户信息
        User user = baseLoginService.getSysUser();
        if (null == user || StringUtils.isEmpty(user.getId())) {
            return AjaxResult.error(52402171, "获取不到登录账号信息");
        }
        // 记录下载文件
        // 获取文件下载记录下载中，则直接告诉客户下载洪
        ExamResultDownLoadFileTypeEnum fileType = ExamResultDownLoadFileTypeEnum.ZS_BATCH_DOWNLOAD_NO_SIGNATURE;
        ExamResultDataDownLoadRecord projectDataDownLoadRecord = null;
        try {
            projectDataDownLoadRecord = examResultDataDownLoadRecordService.getExamResultDataDownLoadRecord(infoId, user.getOfficeid(), fileType.getType());
        } catch (Exception e) {
            log.error("## batchDownloadCertificateNoSignature error", e);
            return AjaxResult.error(52402172, "文件正在下载中请耐心等待");
        }
        if (null != projectDataDownLoadRecord && ExamResultDownLoadStatusEnum.downloading.getStatus().equals(projectDataDownLoadRecord.getStatus())) {
            return AjaxResult.error(52402172, "文件正在下载中请耐心等待");
        }
        if (null != projectDataDownLoadRecord && ExamResultDownLoadStatusEnum.finish.getStatus().equals(projectDataDownLoadRecord.getStatus())) {
            // 获取下载记录的创建时间
            LocalDateTime recordCreateDate = projectDataDownLoadRecord.getCreateDate();
            // 获取项目下的考生最新的时间
            ZsExamineeInfo student = iZsExamineeInfoService.getLastOneStudentByZsId(infoId);
            if (null != student) {
                LocalDateTime studentUpdateDate = student.getUpdateDate();
                if (recordCreateDate.compareTo(studentUpdateDate) > 0) {
                    return AjaxResult.success("成功", projectDataDownLoadRecord.getFileUrl());
                }
            }

        }
        projectDataDownLoadRecord = new ExamResultDataDownLoadRecord();
        projectDataDownLoadRecord.setId(UUIDUtils.newSortUUID());
        projectDataDownLoadRecord.setExamId(infoId);
        projectDataDownLoadRecord.setOfficeId(user.getOfficeid());
        projectDataDownLoadRecord.setDeptId(user.getOrganizationid());
        projectDataDownLoadRecord.setFileType(fileType.getType());
        projectDataDownLoadRecord.setStatus(ExamResultDownLoadStatusEnum.downloading.getStatus());
        projectDataDownLoadRecord.setRemark(fileType.getDesc());
        projectDataDownLoadRecord.setCreateBy(user.getId());
        projectDataDownLoadRecord.setCreateDate(LocalDateTime.now());
        projectDataDownLoadRecord.setUpdateBy(user.getId());
        projectDataDownLoadRecord.setDelFlag(false);
        projectDataDownLoadRecord.setUpdateDate(LocalDateTime.now());
        examResultDataDownLoadRecordService.save(projectDataDownLoadRecord);
        String fileUrl = iZsInfoService.batchDownloadCertificateNoSignature(infoId, projectDataDownLoadRecord, response);
        if (StringUtils.isNotEmpty(fileUrl)) {
            return AjaxResult.success("成功", fileUrl);
        } else {
            return AjaxResult.error(52402172, "文件正在下载中请耐心等待");
        }
    }

    @ApiOperation(
            value = "导出考生名单",
            notes = "20000:成功;"
    )
    @ApiOperationSort(value = 19)
    @ApiVersion(group = ApiVersionConstant.V2_4_2)
    @GetMapping("/exportCertificateExamineesExcel")
    public void exportCertificateExamineesExcel(@ApiParam(value = "证书ID") @RequestParam String infoId, HttpServletResponse response) throws Exception {
        iZsInfoService.exportCertificateExamineesExcel(infoId, response);
    }


}
